﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Blade.IO;
using System.Collections;
using Blade.Metadata.CliLoader;

namespace Blade.Metadata.PeLoader {
	sealed class CliMetadataHeader {
		public CliMetadataHeader(CursorStream stream, IMetadataLoaderContext context) {
			var reader = stream.AsBinaryReader();
			this._Reserved1 = reader.ReadUInt32(); context.Assert(() => _Reserved1 == 0);
			this.SchemaMajorVersion = reader.ReadByte(); context.Assert(() => SchemaMajorVersion == 2);
			this.SchemaMinorVersion = reader.ReadByte(); context.Assert(() => SchemaMinorVersion == 0);
			this.HeapSizes = reader.ReadBitVector(1);
			this._Reserved2 = reader.ReadByte(); context.Assert(() => _Reserved2 == 1);
			var valid = reader.ReadBitVector(8);
			var sorted = reader.ReadBitVector(8);
			for (MetadataTable tableId = 0; tableId < MetadataTable._MaxTable; tableId++) {
				int rowCount = 0;
				if (valid[(int)tableId]) {
					rowCount = reader.ReadInt32();
				}
#if DEBUG
				if (Tables.Contains(tableId))
#endif
 {
					var table = Tables[tableId];
					table.RowCount = rowCount;
				}
			}
		}

		readonly uint _Reserved1; // == 0
		public readonly byte SchemaMajorVersion;
		public readonly byte SchemaMinorVersion;
		public readonly BitArray HeapSizes;
		readonly byte _Reserved2; // == 1

		public readonly CliMetadataTableCollection Tables = new CliMetadataTableCollection {
			new CliMetadataTable(MetadataTable.Module,
				CliFieldType.Int16,
				CliFieldType.StringRef,
				CliFieldType.GuidRef,
				CliFieldType.GuidRef,
				CliFieldType.GuidRef
			),
			new CliMetadataTable(MetadataTable.TypeRef,
				CliFieldType.ResolutionScope,
				CliFieldType.StringRef,
				CliFieldType.StringRef
			),
			new CliMetadataTable(MetadataTable.TypeDef,
				CliFieldType.Int32,
				CliFieldType.StringRef,
				CliFieldType.StringRef,
				CliFieldType.TypeDefOrRef,
				CliFieldType.Field,
				CliFieldType.MethodDef
			),
			new CliMetadataTable(MetadataTable.Field,
				CliFieldType.Int16,
				CliFieldType.StringRef,
				CliFieldType.BlobRef
			),
			new CliMetadataTable(MetadataTable.MethodDef,
				CliFieldType.RVA,
				CliFieldType.StringRef,
				CliFieldType.BlobRef
			),
			new CliMetadataTable(MetadataTable.Param,
				CliFieldType.Int16,
				CliFieldType.Int16,
				CliFieldType.StringRef
			),
			new CliMetadataTable(MetadataTable.InterfaceImpl,
				CliFieldType.TypeDef,
				CliFieldType.TypeDefOrRef
			),
			new CliMetadataTable(MetadataTable.MemberRef,
				CliFieldType.MemberRefParent,
				CliFieldType.StringRef,
				CliFieldType.BlobRef
			),
			new CliMetadataTable(MetadataTable.Constant,
				CliFieldType.Int16,
				CliFieldType.HasConstant,
				CliFieldType.BlobRef
			),
			new CliMetadataTable(MetadataTable.CustomAttribute,
				CliFieldType.HasCustomAttribute,
				CliFieldType.CustomAttributeType,
				CliFieldType.BlobRef
			),
			new CliMetadataTable(MetadataTable.FieldMarshal,
				CliFieldType.HasFieldMarshal,
				CliFieldType.BlobRef
			),
		};
	}
}
